63.QT

您所在的位置:网站首页 qt 滑动效果 63.QT

63.QT

2023-07-04 00:50| 来源: 网络整理| 查看: 265

在上章我们学习了62.QT-QScroller实现home界面滑动效果,但是该界面是实现的上下滑动效果,如果想模拟手机home滑动界面,则需要实现左右滑动效果.

本章,则重写QStackedWidget类,来实现模拟手机home界面左右滑动效果.

1.SmoothStackedWidget类实现

demo界面如下图所示(创建了4个子界面):

效果图如下所示(支持快滑,慢滑):

如果是慢滑,则根据当前滑到的界面处于哪一页占比更多,则就跳到哪里.

同样也支持边缘滑动检测(已在最边缘时,则滑动速率减慢,告诉用户已到边缘):

2.代码实现

头文件如下所示:

#ifndef SMOOTHSTACKEDWIDGET_H #define SMOOTHSTACKEDWIDGET_H #include #include #include #include #include #include class SmoothStackedWidget : public QStackedWidget { Q_OBJECT #define SMOOTH_MAX_MS 900 #define SMOOTH_EDGE_MOVE_RATIO 0.14 //边缘移动系数,范围0~1,越低越慢 typedef enum tagScrollMouseDragInfo { MOUSE_RELEASE = 0, //鼠标离开 MOUSE_PRESS = 1, //按下 MOUSE_PRESS_MOVE = 2, //按下移动 MOUSE_RELEASE_MOVE = 3 //鼠标离开并滑动 }Scroll_Mouse_Drag_INFO_E; typedef enum tagSmoothAnimationSwitchInfo { SWITCH_PRE = -1, //切换上一页 SWITCH_NONE = 0, //不切换 SWITCH_NEXT = 1, //切换下一页 }AnimationSwitch_Drag_INFO_E; Scroll_Mouse_Drag_INFO_E m_dragFlag = MOUSE_RELEASE; AnimationSwitch_Drag_INFO_E m_switchFlag = SWITCH_NONE; QWidget *m_parent; QWidget m_smoothWidget; int m_smoothCurrentIndex=-1; QPropertyAnimation *animation; float m_smoothMovePos; bool eventFilter(QObject *obj, QEvent *evt) override; void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; void SmoothLoadPixmap(bool isSmoothUpdate = false); void SmoothStartMove(); void SmoothMove(int offset); void SmoothAnimationStart(int startPos, int endPos, int durationMs); void SmoothAnimationInit(); public: explicit SmoothStackedWidget(QWidget *parent = nullptr); int addWidget(QAbstractScrollArea *w); int addWidget(QWidget *w); void setCurrentIndex(int index); void removeWidget(QWidget *w); void IconUpdate(); //刷新页数标签 void UpdateSmooth(); signals: protected slots: void OnSmoothAnimationFinished(); }; #endif // SMOOTHSTACKEDWIDGET_H

其中eventFilter()函数如下所示:

当鼠标(手指)按下移动时,则调用SmoothMove()来显示滑动界面.

当鼠标(手指)松开后,则调用SmoothAnimationStart()来实现界面移动(到底是切换上一页、还是切换下一页、还是当前页).

bool SmoothStackedWidget::eventFilter(QObject *obj, QEvent *evt) { QMouseEvent *mouse = dynamic_cast(evt); QWidget *w = dynamic_cast(obj); static int pressPoint_x = 0; //按下的坐标 static int dragPoint_x = -1; //拖动时的坐标 static qint64 pressMSec ; if(mouse && w && animation->state() == QAbstractAnimation::Stopped) { if( mouse->type() ==QEvent::MouseButtonPress) //首次按下 { pressMSec = QDateTime::currentDateTime().toMSecsSinceEpoch(); //记录按下的时间 dragPoint_x = mouse->pos().x(); //当前坐标 pressPoint_x = dragPoint_x; //按下的位置 m_dragFlag = MOUSE_PRESS; } else if(mouse->type() == QEvent::MouseButtonRelease && m_dragFlag == MOUSE_PRESS) //未移动 { m_dragFlag = MOUSE_RELEASE; } else if(mouse->type() == QEvent::MouseMove && m_dragFlag == MOUSE_PRESS) //初次滑动,判断移动阀值,避免误操作 { if(qAbs(dragPoint_x - mouse->pos().x()) > 3) //判断移动阀值,避免误操作 { dragPoint_x = mouse->pos().x(); SmoothStartMove(); m_dragFlag = MOUSE_PRESS_MOVE; } } else if(mouse->type() == QEvent::MouseMove && m_dragFlag== MOUSE_PRESS_MOVE ) //正在滑动 { int offset = ( mouse->pos().x() - dragPoint_x); SmoothMove(offset); dragPoint_x = mouse->pos().x(); } else if(mouse->type() == QEvent::MouseButtonRelease && m_dragFlag == MOUSE_PRESS_MOVE) //滑动结束,启动平滑滑动 { int durationMs= QDateTime::currentDateTime().toMSecsSinceEpoch()-pressMSec; SmoothAnimationStart(pressPoint_x,mouse->pos().x(),durationMs); m_dragFlag = MOUSE_RELEASE; } } return QWidget::eventFilter(obj,evt); }

SmoothAnimationStart()函数如下所示:

void SmoothStackedWidget::SmoothAnimationStart(int startPos, int endPos, int durationMs) { int pixelPerSecond=qAbs(endPos - startPos)*1000/durationMs; //计算每秒像素点 m_switchFlag = SWITCH_NONE; int moveX = qAbs(m_smoothWidget.x()); float temp = width()*0.5; int animationEndX; //慢速滑动(速度过慢||时间过长),则根据当前滑到哪里,就跳到哪里 if(pixelPerSecond 1000) { if(moveX < (temp)) { //[0,width/2] = 上一页 if(currentIndex()==0) { animationEndX = -width(); } else { animationEndX = 0; m_switchFlag = SWITCH_PRE; } } else if(moveX < (temp*3)) { //[width/2,width*3/2] = 当前一页 animationEndX = -width(); } else { if(currentIndex()==(count()-1)) { //[width*3/2,width*2] = 下一页 animationEndX = -width(); } else { animationEndX = -width()*2; m_switchFlag = SWITCH_NEXT; } } } else {    // 否则就是快速滑动 if(startPos < endPos) { //向右滑动 if(currentIndex()==0) { animationEndX = -width(); } else { animationEndX = 0; m_switchFlag = SWITCH_PRE; } } else { //向左滑动 if(currentIndex()==(count()-1)) { animationEndX = -width(); } else { animationEndX = -width()*2; m_switchFlag = SWITCH_NEXT; } } } //根据每秒滑动像素点,来计算滑动时长. int animationDuration = durationMs; float xOffsetRatio = qAbs(animationEndX - m_smoothWidget.x()) / (static_cast(width())); //计算滑动占整屏比例 if(animationDuration > (SMOOTH_MAX_MS * xOffsetRatio)) //滑动时间过大,则重置 animationDuration = SMOOTH_MAX_MS * xOffsetRatio; animation->setDuration(animationDuration); animation->setStartValue(m_smoothWidget.geometry()); animation->setEndValue(QRect(animationEndX, m_smoothWidget.y(), m_smoothWidget.width(), m_smoothWidget.height())); animation->start(); }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3